#include <iostream>
#include <boost/bind.hpp>

#include "ConcurrentTcpConnection.h"
#include "RequestHandler.h"
#include "RequestParser.h"


using namespace boost::asio;
using namespace std;


ConcurrentTcpConnection::ConcurrentTcpConnection(io_service &ioService)
	: _socket(ioService),
	  _strand(ioService)
{
}

void ConcurrentTcpConnection::Start()
{
	_socket.async_read_some(buffer(_buffer),
		_strand.wrap(boost::bind(&ConcurrentTcpConnection::HandleRead, shared_from_this(),
			placeholders::error, placeholders::bytes_transferred)));
}

void ConcurrentTcpConnection::HandleRead(const boost::system::error_code &e, size_t bytesTransferred)
{
	if (e)
	{
		// If an error occurs then no new asynchronous operations are started. This
		// means that all shared_ptr references to the connection object will
		// disappear and the object will be destroyed automatically after this
		// handler returns. The connection class's destructor closes the socket.
		return;
	}

	boost::tribool result;
    boost::tie(result, boost::tuples::ignore) = _requestParser.Parse(_request, _buffer.data(),
																		_buffer.data() + bytesTransferred);

    if (result)
    {
		RequestHandler::HandleRequest(_request, _reply);

		async_write(_socket, _reply.ToBuffers(),
			_strand.wrap(
				boost::bind(&ConcurrentTcpConnection::HandleWrite, shared_from_this(), placeholders::error)));
    }
    else if (!result)
    {
		_reply = Reply::StockReply(Reply::BadRequest);
		async_write(_socket, _reply.ToBuffers(),
			_strand.wrap(
				boost::bind(&ConcurrentTcpConnection::HandleWrite, shared_from_this(), placeholders::error)));
    }
    else
    {
		_socket.async_read_some(buffer(_buffer),
			_strand.wrap(
				boost::bind(&ConcurrentTcpConnection::HandleRead, shared_from_this(),
					placeholders::error, placeholders::bytes_transferred)));
    }
}

void ConcurrentTcpConnection::HandleWrite(const boost::system::error_code &e)
{
	if (e)
	{
		// No new asynchronous operations are started. This means that all shared_ptr
		// references to the connection object will disappear and the object will be
		// destroyed automatically after this handler returns. The connection class's
		// destructor closes the socket.
		return;	
	}

	// Initiate graceful connection closure.
	boost::system::error_code ignored_ec;
	_socket.shutdown(ip::tcp::socket::shutdown_both, ignored_ec);
}